import { Col } from "../core/data_ext";

const { executeInEditMode, ccclass, property } = cc._decorator;

const ShaderPropertyMap = new Map();

export function ShaderProperty() {
    return (target: Object, property: string): void => {
        if (!ShaderPropertyMap.get(target.constructor)) {
            ShaderPropertyMap.set(target.constructor, []);
        }
        let propList = ShaderPropertyMap.get(target.constructor);
        propList.push(property);
    };
}

@ccclass
@executeInEditMode
export default class ShaderBase extends cc.Component {
    refresh(): void { }

    private __properties: Col<any> = {};
    private __initProperties() {
        if (CC_EDITOR) {
            return;
        }
        const PropList = ShaderPropertyMap.get(this.constructor);
        if (PropList) {
            let self = this;
            PropList.forEach(prop => {
                self.__properties[prop] = this[prop];
                delete this[prop];
                //绑定属性
                Object.defineProperty(this, prop, {
                    get() {
                        return self.__properties[prop];
                    },
                    set(newValue) {
                        self.__properties[prop] = newValue;
                        self.material.setProperty(prop, newValue);
                    }
                });
            });
        }
    }
    protected onLoad(): void {
        this.__initProperties();
        this.refresh();
    }
    protected _rc: cc.RenderComponent = null;
    get rc() {
        if (!this._rc) {
            let rc = this.getComponent(cc.RenderComponent) || this.addComponent(cc.RenderComponent);
            if (!rc) {
                cc.error("ShaderBase::sprite, error: 不能获得或添加cc.RenderComponent组件。");
                return null;
            }
            this._rc = rc;
        }
        return this._rc;
    }

    protected _material: cc.Material = null;
    get material() {
        if (!this._material) {
            this._material = this.rc.getMaterial(0);
        }
        return this._material;
    }

    @property({ editorOnly: true, displayName: "实时编辑更新" })
    editorViewUpdate = false;
    protected lateUpdate(dt: number): void {
        if (CC_EDITOR && this.editorViewUpdate) {
            const PropList = ShaderPropertyMap.get(this.constructor);
            if (PropList) {
                PropList.forEach(prop => {
                    this.material.setProperty(prop, this[prop]);
                });
            }
        }
    }

};